home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / PCI Driver Development Kit / • Samples / Driver Samples / SCSI samples / SCSI 950629 / NCR_MiniTest / MiniDriverTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-20  |  26.6 KB  |  1,053 lines  |  [TEXT/MPCC]

  1. /*                                    MiniDriverTest.c                                */
  2. /*
  3.  * MiniDriverTest.c
  4.  * Copyright © 1994-95 Apple Computer Inc. All Rights Reserved.
  5.  */
  6. /*    .___________________________________________________________________________________.
  7.       | This is a very simple test program for the PCI sample driver. It has not been        |
  8.     | compiled for, or tested in, 68000 emulation mode. It is also pretty ugly: it was    |
  9.     | written quickly, and while I was debugging the driver. It is not a prize example    |
  10.     | of production software. All output is written to the LogLibrary.                    |
  11.     |                                                                                    |
  12.     | With no devices attached, each cycle (kSCSITrials) takes about 15 seconds.        |
  13.     .___________________________________________________________________________________.
  14.  */
  15. #define TEST_DRIVER                1
  16. #include <NCRDriverPrivate.h>
  17. #include <Devices.h>
  18. #include <Fonts.h>
  19. #include <ToolUtils.h>
  20. #include <SegLoad.h>
  21. #include <SCSI.h>
  22. #include "MacSCSICommand.h"
  23. #include "LogLibrary.h"
  24.  
  25. #ifndef FALSE
  26. #define FALSE                0
  27. #define TRUE                1
  28. #endif
  29.  
  30. #define kFirstSCSITargetID    0
  31. #define kMaxSCSITargetID    7
  32. #define kSCSITrials            1            /* -1 to exclude, 0 to run forever    */
  33. #define kISRTrials            1            /* -1 to exclude, 0 to run forever    */
  34. #define kFirstBlock            1000
  35. #define kLastBlock            100
  36. /*
  37.  * if kMinBlocks >kMaxBlocks, the transfer length will change with each request.
  38.  */
  39. #define kMinBlocks            1            /* Must be at least 1                */
  40. /*
  41.  * Because we use a 6-byte read command, kMaxBlocks may not exceed 128
  42.  */
  43. #define kMaxBlocks            64            /* Should be >= kMinBlocks            */
  44. #define kTimeout            2000L
  45. #define kReadBufferSize        2048        /* Big enough for CD-ROMs            */
  46.  
  47. short                        gDriverRefNum;
  48. short                        gUnitIndex;
  49. short                        gSCSITargetID;
  50. short                        gSCSITargetLUN = 0;
  51. short                        gTrials;
  52. Boolean                        gQuitNow;
  53. LogRecordPtr                gLogRecordPtr;
  54. MenuHandle                    gAppleMenu;
  55. MenuHandle                    gFileMenu;
  56. EventRecord                    gEventRecord;
  57. Boolean                        gInForeground;
  58. IOParam                        gIOParam;
  59. NCRSCSIParam                gNCRSCSIParam;
  60. Ptr                            gReadBufferPtr;
  61. Str255                        gDriverName;
  62. unsigned long                gReadBufferSize;
  63. unsigned long                gCurrentBlockLength;
  64. unsigned long                gDeviceSize;
  65.  
  66. OSErr                        OpenNextDevice(void);
  67. void                        DoEventLoop(void);
  68. void                        DoMouseEvent(void);
  69. void                        DoCommand(
  70.         long                    menuChoice
  71.     );
  72. #define MENU_Apple            1
  73. #define MENU_File            256
  74. #define kAppleAbout            1
  75. #define kFileQuit            1
  76.  
  77. /*
  78.  * SCSI commands
  79.  */
  80. void                        DoDeviceTest(void);
  81. void                        DoISRTest(void);
  82. OSErr                        DoOneISRTest(void);
  83. OSErr                        DoBusReset(void);
  84. OSErr                        DoTestUnitReady(void);
  85. OSErr                        DoDeviceInquiry(void);
  86. OSErr                        DoReadCapacity(void);
  87. OSErr                        DoReadAllBlocks(void);
  88. OSErr                        DoReadBlock(
  89.         unsigned long            blockNumber,
  90.         unsigned long            nBlocks,
  91.         Boolean                    dumpBlock
  92.     );
  93. Boolean                        DoRequestSense(            /* TRUE if Unit Attention        */
  94.         unsigned short            targetID,            /* SCSI Bus ID                    */
  95.         unsigned short            targetLUN            /* SCSI LUN -- not supported    */
  96.     );
  97. OSErr                        DoIORundown(void);
  98. unsigned long                SCSIGetCommandLength(
  99.         const unsigned char        *cmdBlock
  100.     );
  101. Boolean                        ShowRequestSense(        /* TRUE if Unit Attention        */
  102.         unsigned short            targetID,            /* SCSI Bus ID                    */
  103.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  104.         OSErr                    callStatus,            /* DoDriverIO Request Sense        */
  105.         const SCSI_Sense_Data    *sense,
  106.         unsigned long            actualTransferCount
  107.     );
  108. #define AppendChar(result, theChar)    do {                \
  109.         StringPtr        _dst = (result);                \
  110.         _dst[++_dst[0]] = theChar;                        \
  111.     } while (0)
  112. void                        ShowMemory(
  113.         const Ptr                memStart,
  114.         unsigned long            byteCount
  115.     );
  116.  
  117. void                        AppendHexLeadingZeros(
  118.         StringPtr                result,
  119.         unsigned long            value,
  120.         short                    fieldWidth
  121.     );
  122. void                        AppendSigned(
  123.         StringPtr                result,
  124.         signed long                value
  125.     );
  126. void                        AppendUnsigned(
  127.         StringPtr                result,
  128.         unsigned long            value
  129.     );
  130.  
  131. /*
  132.  * NCR Driver commands
  133.  */
  134. OSErr                        DoNCRDriverIOWithSense(
  135.         unsigned short            driverAction,        /* Input, output, or nothing    */
  136.         unsigned short            targetID,            /* SCSI Bus ID                    */
  137.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  138.         const unsigned char        *scsiCommand,        /* SCSI Command itself            */
  139.         Ptr                        dataBufferPtr,        /* User data buffer or NULL     */
  140.         unsigned long            transferCount,
  141.         unsigned long            *actualTransferCount
  142.     );
  143. OSErr                        DoNCRDriverIO(
  144.         unsigned short            driverAction,        /* Input, output, or nothing    */
  145.         unsigned short            targetID,            /* SCSI Bus ID                    */
  146.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  147.         const unsigned char        *scsiCommand,        /* SCSI Command itself            */
  148.         Ptr                        dataBufferPtr,        /* User data buffer or NULL     */
  149.         unsigned long            transferCount,
  150.         unsigned long            *actualTransferCount
  151.     );
  152. /*
  153.  * A handy macro to clear a (small) structure.
  154.  */
  155. void                        ClearMemory(
  156.         register Ptr            memPtr,
  157.         register Size            memSize
  158.     );
  159. #undef CLEAR
  160. #define CLEAR(what)    ClearMemory((Ptr) &what, sizeof what)
  161.  
  162. #define ShowString(string) WriteLogEntry(gLogRecordPtr, 'Test', LogStringFormat, (string))
  163. #define ShowStatusString(status, string)                     \
  164.     WriteLogEntry(gLogRecordPtr, 'Test',                    \
  165.         LogFormat2(kLogFormatSigned, kLogFormatString),        \
  166.         (status), (string))
  167. #define ShowHex(value, string)                                \
  168.     WriteLogEntry(                                            \
  169.         gLogRecordPtr, 'Test',                                \
  170.         LogFormat2(kLogFormatAddress, kLogFormatString),    \
  171.         (unsigned long) (value),                            \
  172.         (string)                                            \
  173.     )
  174. #define ShowDecimal(value, string)                            \
  175.     WriteLogEntry(                                            \
  176.         gLogRecordPtr, 'Test',                                \
  177.         LogFormat2(kLogFormatSigned, kLogFormatString),        \
  178.         (signed long) (value),                                \
  179.         (string)                                            \
  180.     )
  181.  
  182. void
  183. main(void)
  184. {
  185.         OSErr                status;
  186.         short                i;
  187.         
  188.         gLogRecordPtr = MakeLogRecord("MiniDriverTest", 128);
  189.         ShowString("\pHello World!");
  190.         MaxApplZone();
  191.         InitGraf(&qd.thePort);
  192.         InitFonts();
  193.         InitWindows();
  194.         InitMenus();
  195.         TEInit();
  196.         InitDialogs(0);
  197.         for (i = 0; i < 8; i++)
  198.             MoreMasters();
  199.         HNoPurge((Handle) GetCursor(watchCursor));
  200.         SetCursor(*GetCursor(watchCursor));
  201.         gReadBufferSize = kReadBufferSize * kMaxBlocks;
  202.         gReadBufferPtr = NewPtrClear(gReadBufferSize);
  203.         if (gReadBufferPtr == NULL) {
  204.             ShowString("\pNo memory for read buffer");
  205.             ExitToShell();
  206.         }
  207.         gAppleMenu = NewMenu(MENU_Apple, "\p\024");
  208.         AppendMenu(gAppleMenu, "\p(No About;(-");
  209.         AppendResMenu(gAppleMenu, 'DRVR');
  210.         gFileMenu = NewMenu(MENU_File, "\pFile");
  211.         AppendMenu(gFileMenu, "\pQuit/Q");
  212.         InsertMenu(gAppleMenu, 0);
  213.         InsertMenu(gFileMenu, 0);
  214.         DrawMenuBar();
  215.         for (; (status = OpenNextDevice()) == noErr; gUnitIndex++) {
  216.             if (status != noErr)
  217.                 ShowStatusString(status, gDriverName);
  218.             else {
  219.                 DoDeviceTest();
  220.                 ShowString("\pDriver test complete");
  221.             }
  222.         }
  223.         ShowString("\pAll tests complete");
  224.         ExitToShell();
  225. }
  226.  
  227. /*
  228.  * Find the next device (after this one) that has our device name.
  229.  */
  230. OSErr
  231. OpenNextDevice(void)
  232. {
  233.         OSErr                    status;
  234.         ItemCount                items;
  235.         DriverRefNum            refNum;
  236.         UnitNumber                unusedUnitNumber;
  237.         DriverFlags                driverFlags;
  238.         DriverOpenCount            driverOpenCount;
  239.         RegEntryID                deviceID;
  240.         CFragHFSLocator            cFragHFSLocator;
  241.         CFragConnectionID        cFragConnectionID;
  242.         DriverEntryPointPtr        fragmentMain;
  243.         DriverDescription        driverDescription;
  244.  
  245.         for (;; gUnitIndex += 1) {
  246.             if (gUnitIndex > HighestUnitNumber()) {
  247.                 status = badUnitErr;
  248.                 break;
  249.             }
  250.             items = 1;
  251.             status = LookupDrivers(gUnitIndex, gUnitIndex, FALSE, &items, &refNum);
  252.             if (status != noErr)
  253.                 break;
  254.             if (items == 1) {
  255.                 /*
  256.                  * We have found a driver (but not necessarily ours).
  257.                  */
  258.                 status = GetDriverInformation(
  259.                             refNum,
  260.                             &unusedUnitNumber,
  261.                             &driverFlags,
  262.                             &driverOpenCount,
  263.                             gDriverName,
  264.                             &deviceID,
  265.                             &cFragHFSLocator,
  266.                             &cFragConnectionID,
  267.                             &fragmentMain,
  268.                             &driverDescription
  269.                         );
  270.                 if (status != noErr)
  271.                     break;
  272.                 if (PStrCmp(gDriverName, kDriverNamePString) == 0) {
  273.                     /*
  274.                      * This is our device. Try to open it. (This presumes that the
  275.                      * driver was installed "load on discovery.")
  276.                      */
  277.                     status = OpenInstalledDriver(refNum, 3); /* Allow read/write    */
  278.                     if (status != noErr) {
  279.                         ShowStatusString(status, "\pCan't open installed driver");
  280.                         continue;
  281.                     }
  282.                     else {
  283.                         gDriverRefNum = refNum;
  284.                         break;
  285.                     }
  286.                 } /* If this is our device */
  287.             } /* If LookupDrivers found a device */
  288.         } /* Unit number loop */
  289.         return (status);
  290. }
  291.  
  292. void
  293. DoDeviceTest(void)
  294. {
  295.         OSErr                status;
  296.         unsigned long        startBlock;
  297.         unsigned long        nBlocks;
  298.  
  299.         ShowDecimal(gDriverRefNum, "\pDo Bus Reset");
  300.         status = DoBusReset();
  301.         if (status != noErr)
  302.             ShowStatusString(status, "\pDo Bus Reset failed");
  303.         else {
  304.             for (gTrials = 0;
  305.                         gQuitNow == FALSE
  306.                         && (kSCSITrials == 0 || gTrials < kSCSITrials);
  307.                         gTrials++) {
  308.                 ShowDecimal(gTrials, "\pTrial");
  309.                 for (gSCSITargetID = kFirstSCSITargetID;
  310.                             gQuitNow == FALSE && gSCSITargetID <= kMaxSCSITargetID;
  311.                             gSCSITargetID++) {
  312.                     DoEventLoop();
  313.                     if (gQuitNow == FALSE) {
  314.                         ShowDecimal(gSCSITargetID, "\pTarget");
  315.                         status = DoTestUnitReady();
  316.                         DoEventLoop();
  317.                         if (status == noErr)
  318.                             status = DoDeviceInquiry();
  319.                         DoEventLoop();
  320.                         if (status == noErr)
  321.                             status = DoReadCapacity();
  322.                         DoEventLoop();
  323.                         ShowStatusString(status, "\pDoDeviceTest after init");
  324.                         if (1 && status == noErr) {        /* Turn on for device exercise    */
  325.                             nBlocks = kMinBlocks;
  326.                             for (startBlock = 0;
  327.                                     startBlock < (gDeviceSize - kMaxBlocks);
  328.                                     startBlock++) {
  329.                                 if (nBlocks > kMaxBlocks)
  330.                                     nBlocks = kMinBlocks;
  331.                                 DoEventLoop();
  332.                                 if (DoReadBlock(startBlock, nBlocks, FALSE) != noErr)
  333.                                     break;
  334.                                 ++nBlocks;
  335.                                 if (gQuitNow) {
  336.                                     ShowString("\pQuit requested");
  337.                                     break;
  338.                                 }
  339.                             }
  340.                         }
  341.                     }
  342.                 }
  343.             }
  344.         }
  345.         ShowStatusString(status, "\pDoDeviceTest exits");
  346. }
  347.  
  348. void
  349. DoISRTest(void)
  350. {
  351.         OSErr                        status;
  352.         
  353.         for (status = noErr, gTrials = 0;
  354.                     gQuitNow == FALSE
  355.                     && (kISRTrials == 0 || gTrials < kISRTrials);
  356.                     gTrials++) {
  357.             DoEventLoop();
  358.             ShowDecimal(gTrials, "\pISR Trial");
  359.             status = DoOneISRTest();
  360.             if (status != noErr) {
  361.                 ShowStatusString(status, "\pISR Test failed");
  362.                 gQuitNow = TRUE;
  363.                 break;
  364.             }
  365.         }
  366. }
  367.  
  368. OSErr
  369. DoOneISRTest(void)
  370. {
  371.         OSErr                    status;
  372.         unsigned char            dummyBuffer;
  373. #define NCR    (gNCRSCSIParam)
  374. #define PB    (gIOParam)
  375.  
  376.         status = noErr;
  377.         /*
  378.          * Setup the parameter block
  379.          */
  380.         CLEAR(PB);
  381.         CLEAR(NCR);
  382.         PB.ioRefNum = gDriverRefNum;
  383.         NCR.driverAction = kNCRDriverNoDataPhase;
  384.         NCR.targetID = kNCRMemoryTestBusID;
  385.         NCR.watchdogTimeout = kTimeout;        /* Presumably a two second timeout    */
  386.         PB.ioBuffer = (Ptr) &dummyBuffer;
  387.         PB.ioReqCount = 1;
  388.         PB.ioMisc = (Ptr) &gNCRSCSIParam;
  389.         status = PBReadSync((ParmBlkPtr) &PB);
  390.         return ((status != noErr) ? status : PB.ioResult);
  391. #undef PB
  392. #undef NCR
  393. }
  394.  
  395. void
  396. DoEventLoop(void)
  397. {
  398.         long                            menuChoice;
  399.         register WindowPtr                theWindow;
  400.         GrafPtr                            savePort;
  401.         Boolean                            isActivating;
  402.         
  403.         WaitNextEvent(
  404.             everyEvent,
  405.             &gEventRecord,
  406.             10L,
  407.             NULL
  408.         );
  409.         theWindow = FrontWindow();
  410.         switch (gEventRecord.what) {
  411.         case nullEvent:
  412.             break;
  413.         case keyDown:
  414.         case autoKey:
  415.             if ((gEventRecord.message & charCodeMask) == '.'
  416.              && (gEventRecord.modifiers & cmdKey) != 0) {
  417.                 FlushEvents(keyDown | autoKey, 0);
  418.                 gQuitNow = TRUE;
  419.             }
  420.             else if ((gEventRecord.modifiers & cmdKey) != 0) {
  421.                 if (gEventRecord.what == keyDown) {
  422.                     menuChoice = MenuKey(gEventRecord.message & charCodeMask);
  423.                     if (HiWord(menuChoice) != 0)
  424.                         DoCommand(menuChoice);
  425.                 }
  426.             }
  427.             break;
  428.         case mouseDown:
  429.             DoMouseEvent();
  430.             break;
  431.         case updateEvt:
  432.             theWindow = (WindowPtr) gEventRecord.message;
  433.             GetPort(&savePort);
  434.             SetPort(theWindow);
  435.             BeginUpdate(theWindow);
  436.             EraseRect(&theWindow->portRect);
  437.             DrawControls(theWindow);
  438.             DrawGrowIcon(theWindow);
  439.             EndUpdate(theWindow);
  440.             SetPort(savePort);
  441.             break;
  442.         case activateEvt:
  443.             theWindow = (WindowPtr) gEventRecord.message;
  444.             isActivating = ((gEventRecord.modifiers & activeFlag) != 0);
  445.             goto activateEvent;
  446.             break;
  447.         case osEvt:
  448.             switch (((unsigned long) gEventRecord.message) >> 24) {
  449.             case mouseMovedMessage:
  450.                 break;
  451.             case suspendResumeMessage:
  452.                 isActivating = ((gEventRecord.message & 0x01) != 0);
  453. activateEvent:        if (isActivating) {
  454.                     /*
  455.                      * Activate this window. Activate events define theWindow
  456.                      * from the event record, while suspend/resume uses the
  457.                      * pre-set FrontWindow value.
  458.                      */
  459.                     SelectWindow(theWindow);
  460.                     (void) TEFromScrap();
  461.                 }
  462.                 gInForeground = isActivating;
  463.                 break;
  464.             }
  465.             break;
  466.         }
  467. }
  468.  
  469.  
  470. /*
  471.  * DoMouseEvent
  472.  * The user clicked on something. Handle application-wide processing here, or call
  473.  * a Catalog Browser function for specific action.
  474.  */
  475. void
  476. DoMouseEvent(void)
  477. {
  478.         WindowPtr        theWindow;
  479.         short            whichPart;
  480.         
  481.         whichPart = FindWindow(gEventRecord.where, &theWindow);
  482.         switch (whichPart) {
  483.         case inMenuBar:
  484.             InitCursor();
  485.             DoCommand(MenuSelect(gEventRecord.where));
  486.             break;
  487.         }
  488. }
  489.  
  490. void
  491. DoCommand(
  492.         long                    menuChoice
  493.     )
  494. {
  495.         short                    menuItem;
  496.         Str255                    menuText;
  497.         GrafPtr                    savePort;
  498.  
  499.         menuItem = LoWord(menuChoice);
  500.         switch (HiWord(menuChoice)) {
  501.         case MENU_Apple:
  502.             if (menuItem != kAppleAbout) {
  503.                 GetMenuItemText(gAppleMenu, menuItem, menuText);
  504.                 GetPort(&savePort);
  505.                 OpenDeskAcc(menuText);
  506.                 SetPort(savePort);
  507.             }
  508.             break;
  509.         case MENU_File:
  510. gQuitNow = TRUE;
  511.             switch (menuItem) {
  512.             case kFileQuit:
  513.                 gQuitNow = TRUE;
  514.                 break;
  515.             default:
  516.                 DebugStr("\pStrange File Menu");
  517.                 gQuitNow = TRUE;
  518.                 break;
  519.             }
  520.             break;
  521.         }
  522.         HiliteMenu(0);
  523. }
  524.  
  525.  
  526. OSErr
  527. DoBusReset(void)
  528. {
  529.  
  530.         OSErr                    status;
  531.         CntrlParam                pb;
  532.         
  533.         ShowString("\pIn DoBusReset");
  534.         CLEAR(pb);
  535.         pb.ioCRefNum = gDriverRefNum;
  536.         pb.csCode = kControlDoSCSIBusReset;
  537.         status = PBControlSync((ParmBlkPtr) &pb);
  538.         ShowStatusString(status, "\pDoBusReset PBControl status");
  539.         if (pb.ioResult != noErr) {
  540.             ShowDecimal(pb.ioResult, "\pBus reset failed");
  541.             gQuitNow = TRUE;
  542.         }
  543.         return (status);
  544. }
  545.  
  546. OSErr
  547. DoTestUnitReady(void)
  548. {
  549.         OSErr                    status;
  550.         SCSI_6_Byte_Command        testUnitReady;
  551.         char                    foo[64];
  552.         
  553.         CLEAR(testUnitReady);
  554.         testUnitReady.opcode = kScsiCmdTestUnitReady;
  555.         ShowString("\pCalling TestUnitReady");
  556.         status = DoNCRDriverIOWithSense(
  557.                     kNCRDriverNoDataPhase,
  558.                     gSCSITargetID,
  559.                     gSCSITargetLUN,
  560.                     (unsigned char *) &testUnitReady,
  561.                     (Ptr) foo,                /* PBRead must pass a real buffer    */
  562.                     64,
  563.                     NULL
  564.                 );
  565.         return (status);
  566. }
  567.  
  568. OSErr
  569. DoDeviceInquiry(void)
  570. {
  571.         OSErr                        status;
  572.         SCSI_6_Byte_Command            deviceInquiry;
  573.         SCSI_Inquiry_Data            inquiryData;
  574.         
  575.         CLEAR(deviceInquiry);
  576.         deviceInquiry.opcode = kScsiCmdInquiry;
  577.         deviceInquiry.len = sizeof inquiryData;
  578.         CLEAR(inquiryData);
  579.         ShowString("\pCalling DeviceInquiry");
  580.         status = DoNCRDriverIOWithSense(
  581.                     kNCRDriverInputAllowed,
  582.                     gSCSITargetID,
  583.                     gSCSITargetLUN,
  584.                     (unsigned char *) &deviceInquiry,
  585.                     (Ptr) &inquiryData,
  586.                     sizeof inquiryData,
  587.                     NULL
  588.                 );
  589.         if (status == noErr) {
  590.             inquiryData.vendor[-1] = 8 + 16 + 4;
  591.             ShowString(&inquiryData.vendor[-1]);
  592.         }
  593.         return (status);
  594. #undef INQUIRY
  595. }
  596.  
  597. OSErr
  598. DoReadCapacity(void)
  599. {
  600.         OSErr                        status;
  601.         SCSI_12_Byte_Command        capacityCmd;
  602.         struct SCSI_Capacity_Data     capacityData;
  603.  
  604.         ShowString("\pDoReadCapacity");
  605.         CLEAR(capacityCmd);
  606.         CLEAR(capacityData);
  607.         /*
  608.          * The 6-byte read command can read up to 128 blocks of data (1-127 reads that
  609.          * number of blocks, while zero reads 128 blocks). For more flexibility, you
  610.          * should use the 10-byte Read command.
  611.          */
  612.         capacityCmd.opcode = kScsiCmdReadCapacity;
  613.         status = DoNCRDriverIOWithSense(
  614.                     kNCRDriverInputAllowed,
  615.                     gSCSITargetID,
  616.                     gSCSITargetLUN,
  617.                     (unsigned char *) &capacityCmd,
  618.                     (Ptr) &capacityData,
  619.                     sizeof capacityData,
  620.                     NULL
  621.                 );
  622.         if (status == noErr) {
  623.             gDeviceSize =
  624.                 ( (capacityData.lbn4 << 24)
  625.                 | (capacityData.lbn3 << 16)
  626.                 | (capacityData.lbn2 <<  8)
  627.                 | (capacityData.lbn1      )
  628.                 );
  629.             gCurrentBlockLength =
  630.                 ( (capacityData.len4 << 24)
  631.                 | (capacityData.len3 << 16)
  632.                 | (capacityData.len2 <<  8)
  633.                 | (capacityData.len1      )
  634.                 );
  635.             WriteLogEntry(gLogRecordPtr, 'Test',
  636.                 LogFormat3(kLogFormatUnsigned, kLogFormatUnsigned, kLogFormatString),
  637.                 gDeviceSize, gCurrentBlockLength,
  638.                 "\pDevice Size, Block Length"
  639.             );
  640.         }
  641.         return (status);
  642. }
  643.  
  644. OSErr
  645. DoReadBlock(
  646.         unsigned long            blockNumber,
  647.         unsigned long            nBlocks,
  648.         Boolean                    dumpBlock
  649.     )
  650. {
  651.         OSErr                    status;
  652.         SCSI_6_Byte_Command        readData;
  653.         unsigned long            i;
  654.         Boolean                    readSomething;
  655.         unsigned long            transferLength;
  656.         unsigned long            actualTransferLength;
  657.  
  658.         transferLength = nBlocks * gCurrentBlockLength;
  659.         ClearMemory(gReadBufferPtr, transferLength);    
  660.         CLEAR(readData);    
  661.         /*
  662.          * The 6-byte read command can read up to 128 blocks of
  663.          * data (1-127 reads that number of blocks, while zero
  664.          * reads 128 blocks). For more flexibility, you should
  665.          * use the 10-byte Read command.
  666.          */
  667.         readData.opcode = kScsiCmdRead6;
  668.         readData.len = nBlocks;
  669.         if (readData.len == 0)    /* Zero means 128 */
  670.             readData.len = 1;
  671.         readData.lbn3 = (blockNumber >> 16) & 0xFF;
  672.         readData.lbn2 = (blockNumber >>  8) & 0xFF;
  673.         readData.lbn1 = (blockNumber >>  0) & 0xFF;
  674.         WriteLogEntry(gLogRecordPtr, 'Read',
  675.             LogFormat4(kLogFormatUnsigned, kLogFormatUnsigned,
  676.                 kLogFormatUnsigned, kLogFormatString),
  677.             blockNumber, nBlocks, transferLength,
  678.             "\pRead block"
  679.         );
  680.         status = DoNCRDriverIOWithSense(
  681.                     kNCRDriverInputAllowed,
  682.                     gSCSITargetID,
  683.                     gSCSITargetLUN,
  684.                     (unsigned char *) &readData,
  685.                     (Ptr) gReadBufferPtr,
  686.                     transferLength,
  687.                     &actualTransferLength
  688.                 );
  689.         readSomething = FALSE;
  690.         for (i = 0; i < actualTransferLength; i++) {
  691.             if (gReadBufferPtr[i] != 0) {
  692.                 readSomething = TRUE;
  693.                 break;
  694.             }
  695.         }
  696.         if (dumpBlock) {
  697.             if (readSomething == FALSE)
  698.                 ShowDecimal(blockNumber, "\pReadBlock is NULL after read");
  699.             else {
  700.                 ShowDecimal(blockNumber, "\pReadBlock results");
  701.                 ShowMemory((Ptr) gReadBufferPtr, actualTransferLength);
  702.             }
  703.         }
  704.         if (status == noErr && actualTransferLength != transferLength) {
  705.             ShowString("\pShort transfer");
  706.             status = ioErr;
  707.         }
  708.         return (status);
  709. }
  710.  
  711. OSErr
  712. DoNCRDriverIOWithSense(
  713.         unsigned short            driverAction,        /* Input, output, or nothing    */
  714.         unsigned short            targetID,            /* SCSI Bus ID                    */
  715.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  716.         const unsigned char        *scsiCommand,        /* SCSI Command itself            */
  717.         Ptr                        dataBufferPtr,        /* User data buffer or NULL     */
  718.         unsigned long            transferCount,
  719.         unsigned long            *actualTransferCount
  720.     )
  721. {
  722.         OSErr                    status;
  723.         Boolean                    retry;
  724.         short                    trials;
  725.         
  726.         retry = TRUE;
  727.         for (trials = 0; trials < 3 && retry; trials++) {
  728.             retry = FALSE;
  729.             status = DoNCRDriverIO(
  730.                         driverAction,
  731.                         targetID,
  732.                         targetLUN,
  733.                         scsiCommand,
  734.                         dataBufferPtr,
  735.                         transferCount,
  736.                         actualTransferCount
  737.                     );
  738.             if (status == scsiNonZeroStatus) {
  739.                 retry = DoRequestSense(targetID, targetLUN);
  740.                 if (retry)
  741.                     ShowString("\pRetry after Unit Attention");
  742.             }
  743.         };
  744.         return (status);
  745. }
  746.  
  747. /*
  748.  * Return TRUE if this is Unit Attention
  749.  */
  750. Boolean
  751. DoRequestSense(
  752.         unsigned short            targetID,            /* SCSI Bus ID                    */
  753.         unsigned short            targetLUN            /* SCSI LUN -- not supported    */
  754.     )
  755. {
  756.         OSErr                    status;
  757.         SCSI_6_Byte_Command        requestSense;
  758.         unsigned long            actualTransferCount;
  759.         SCSI_Sense_Data            sense;
  760.         Boolean                    result;
  761.         
  762.         CLEAR(requestSense);
  763.         CLEAR(sense);
  764.         requestSense.opcode = kScsiCmdRequestSense;
  765.         requestSense.len = sizeof sense;
  766.         status = DoNCRDriverIO(
  767.             kNCRDriverInputAllowed,
  768.             targetID,
  769.             targetLUN,
  770.             (unsigned char *) &requestSense,
  771.             (Ptr) &sense,
  772.             sizeof sense,
  773.             &actualTransferCount
  774.         );
  775.         result = ShowRequestSense(targetID, targetLUN, status, &sense, actualTransferCount);
  776.         return (result);
  777. }
  778.  
  779. /*
  780.  * DoNCRDriverIO returns kNCRNonZeroStatus if the target returned CheckCondition.
  781.  */
  782. OSErr
  783. DoNCRDriverIO(
  784.         unsigned short            driverAction,        /* Input, output, or nothing    */
  785.         unsigned short            targetID,            /* SCSI Bus ID                    */
  786.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  787.         const unsigned char        *scsiCommand,        /* SCSI Command itself            */
  788.         Ptr                        dataBufferPtr,        /* User data buffer or NULL     */
  789.         unsigned long            transferCount,
  790.         unsigned long            *actualTransferCount
  791.     )
  792. {
  793.         OSErr                    status;
  794. #define NCR    (gNCRSCSIParam)
  795. #define PB    (gIOParam)
  796.  
  797.         status = noErr;
  798.         /*
  799.          * Setup the parameter block
  800.          */
  801.         CLEAR(PB);
  802.         CLEAR(NCR);
  803.         PB.ioRefNum = gDriverRefNum;
  804.         NCR.driverAction = driverAction;
  805.         NCR.targetID = targetID;
  806.         NCR.logicalUnitNumber = targetLUN;
  807.         NCR.scsiCommandLength = SCSIGetCommandLength(scsiCommand);
  808.         BlockMove(scsiCommand, NCR.scsiCommand, NCR.scsiCommandLength);
  809.         NCR.watchdogTimeout = kTimeout;        /* Presumably a two second timeout    */
  810.         PB.ioMisc = (Ptr) &gNCRSCSIParam;
  811.         PB.ioBuffer = dataBufferPtr;
  812.         PB.ioReqCount = transferCount;
  813.         if ((driverAction & kNCRDriverOutputAllowed) != 0)
  814.             status = PBWriteSync((ParmBlkPtr) &PB);
  815.         else {
  816.             status = PBReadSync((ParmBlkPtr) &PB);
  817.         }
  818.         if (actualTransferCount != NULL)
  819.             *actualTransferCount = PB.ioActCount;
  820.         if (PB.ioResult == ioErr)
  821.             gQuitNow = TRUE;
  822.         WriteLogEntry(
  823.             gLogRecordPtr, 'DoIO',
  824.             LogFormat5(
  825.                 kLogFormatSigned, kLogFormatSigned, kLogFormatUnsigned,
  826.                 kLogFormatUnsigned, kLogFormatString
  827.             ),
  828.             (signed long) status,
  829.             (signed long) PB.ioResult,
  830.             transferCount,
  831.             PB.ioActCount,
  832.             "\pDoDriveriO"
  833.         );
  834.         if (PB.ioResult == scsiCommandTimeout) {
  835.             status = DoIORundown();
  836.             gQuitNow = TRUE;
  837.         }
  838.         return (status);
  839. #undef PB
  840. #undef NCR
  841. }
  842.  
  843. /*
  844.  * The timer fired and we may be stuck with the bus busy. Try to rundown I/O using
  845.  * our private Control call. For the time being, we don't attempt another timeout.
  846.  */
  847. OSErr
  848. DoIORundown(void)
  849. {
  850.         OSErr                    status;
  851.         
  852.         NCRDriverRundownParam    pb;
  853.         
  854.         CLEAR(pb);
  855.         pb.ioCRefNum = gDriverRefNum;
  856.         pb.csCode = kControlDoSCSIRundown;
  857.         pb.watchdogTimeout = kNoSCSITimeout;
  858.         ShowString("\pCalling DoIORundown");
  859.         status = PBControlSync((ParmBlkPtr) &pb);
  860.         ShowStatusString(status, "\pDoIORundown PBControl status");
  861.         gQuitNow = TRUE;
  862.         return (status);
  863. }
  864.  
  865. unsigned long
  866. SCSIGetCommandLength(
  867.         const unsigned char        *cmdBlock
  868.     )
  869. {
  870.         unsigned long            result;
  871.         /*
  872.          * Look at the "group code" in the command operation. Return a parameter
  873.          * error for the reserved (3, 4) and vendor-specific command (6, 7)
  874.          * command groups. Otherwise, set the command length from the group code
  875.          * value as specified in the SCSI-II spec. Then, copy the command block
  876.          * into the parameter block (this centralizes everything for debugging
  877.          * convenience).
  878.          */
  879.         switch (cmdBlock[0] & 0xE0) {
  880.         case (0 << 5):    result = 6;        break;
  881.         case (1 << 5):
  882.         case (2 << 5):    result = 10;    break;
  883.         case (5 << 5):    result = 12;    break;
  884.         default:        result = 0;        break;        /* This results in an error    */
  885.         }
  886.         return (result);
  887. }
  888.  
  889.  
  890. Boolean
  891. ShowRequestSense(
  892.         unsigned short            targetID,            /* SCSI Bus ID                    */
  893.         unsigned short            targetLUN,            /* SCSI LUN -- not supported    */
  894.         OSErr                    callStatus,            /* DoDriverIO Request Sense        */
  895.         const SCSI_Sense_Data    *sense,
  896.         unsigned long            actualTransferCount
  897.     )
  898. {
  899.         Boolean                    result;
  900.         Str255                    work;
  901.         static const StringPtr gSenseKeyText[] = {
  902.             "\p No error",
  903.             "\p Recovered error",
  904.             "\p Not ready",
  905.             "\p Medium error",
  906.             "\p Hardware error",
  907.             "\p Illegal request",
  908.             "\p Unit attention",
  909.             "\p Data protection",
  910.             "\p Blank check",    
  911.             "\p Vendor specific",
  912.             "\p Copy aborted",
  913.             "\p Command aborted",
  914.             "\p Compare equal",    
  915.             "\p Volume overflow",
  916.             "\p Miscompare",
  917.             "\p Reserved"
  918.         };
  919. #define SENSE (*sense)
  920.  
  921.         result = FALSE;
  922.         WriteLogEntry(gLogRecordPtr, 'Sens',
  923.             LogFormat5(kLogFormatUnsigned, kLogFormatUnsigned,
  924.                 kLogFormatSigned, kLogFormatUnsigned, kLogFormatString),
  925.             (UInt32) targetID, (UInt32) targetLUN, (SInt32) callStatus,
  926.             (UInt32) actualTransferCount,
  927.             "\pbus lun stat trans"
  928.         );
  929.         if (actualTransferCount != sizeof SENSE) {
  930.             WriteLogEntry(gLogRecordPtr, 'Sens',
  931.                 LogFormat3(kLogFormatUnsigned, kLogFormatUnsigned, kLogFormatString),
  932.                 (UInt32) actualTransferCount, (UInt32) sizeof SENSE,
  933.                 "\pRead, sizeof sense"
  934.             );
  935.         }
  936.         ShowMemory((Ptr) &SENSE, actualTransferCount);
  937.         PStrCopy(work, "\pSense: ");
  938.         AppendHexLeadingZeros(work, SENSE.errorCode, 2);
  939.         if ((SENSE.errorCode & kScsiSenseInfoMask) != kScsiSenseInfoValid)
  940.             PStrCat(work, "\p Invalid Sense");
  941.         else {
  942.             PStrCat(work, gSenseKeyText[SENSE.senseKey & kScsiSenseKeyMask]);
  943.             if ((SENSE.senseKey & kScsiSenseILI) != 0)
  944.                 PStrCat(work, "\p ILI");
  945.             if ((SENSE.senseKey & kScsiSenseEOM) != 0)
  946.                 PStrCat(work, "\p EOM");
  947.             if ((SENSE.senseKey & kScsiSenseFileMark) != 0)
  948.                 PStrCat(work, "\p EOF");
  949.             WriteLogEntry(gLogRecordPtr, 'Sens', kLogFormatString, work);
  950.             work[0] = 0;
  951.             AppendHexLeadingZeros(work, SENSE.additionalSenseCode & 0xFF, 2);
  952.             PStrCat(work, "\p ");
  953.             AppendHexLeadingZeros(work, SENSE.additionalSenseQualifier & 0xFF, 2);
  954.             PStrCat(work, "\p ASC ASQ");
  955.             result = ((SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseUnitAtn);
  956.         }
  957.         WriteLogEntry(gLogRecordPtr, 'Sens', kLogFormatString, work);
  958.         return (result);
  959. #undef SENSE
  960. }
  961.  
  962.  
  963. void
  964. ShowMemory(
  965.         const Ptr                memStart,
  966.         unsigned long            byteCount
  967.     )
  968. {
  969.         unsigned long            startIndex;
  970.         unsigned long            endIndex;
  971.         unsigned long            i;
  972.         Str255                    work;
  973.  
  974.         /*
  975.          * WriteLogEntry writes up to 40 characters. This is organized as
  976.          *    Start Index                3
  977.          *    4 groups of 4 bytes:    4 * (8 + 1)
  978.          *    One left over for good luck.
  979.          */
  980. if (byteCount > 32) byteCount = 32;
  981.         ShowDecimal(byteCount, "\pMemory Dump");
  982.         for (startIndex = 0; startIndex < byteCount; startIndex += 16) {
  983.             endIndex = startIndex + 16;
  984.             if (endIndex > byteCount)
  985.                 endIndex = byteCount;
  986.             work[0] = 0;
  987.             AppendHexLeadingZeros(work, startIndex, 3);
  988.             for (i = startIndex; i < endIndex; i++) {
  989.                 if ((i & 0x03) == 0x00)
  990.                     AppendChar(work, ' ');    
  991.                 AppendHexLeadingZeros(work, memStart[i], 2);
  992.             }
  993.             ShowString(work);
  994.         }
  995. }
  996.  
  997. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  998.  * Output a string of hex digits with leading zeros. May not move memory. Note that
  999.  * "digits" is the field width, not the number of hex bytes. Debug only.
  1000.  */
  1001. void
  1002. AppendHexLeadingZeros(
  1003.         StringPtr                result,
  1004.         unsigned long            value,
  1005.         short                    fieldWidth
  1006.     )
  1007. {
  1008.         if (--fieldWidth > 0)
  1009.             AppendHexLeadingZeros(result, value >> 4, fieldWidth);
  1010.         value &= 0x0F;
  1011.         AppendChar(result,
  1012.                 (value < 10)
  1013.                 ? value + '0'
  1014.                 : (value + ('A' - 10))
  1015.             );
  1016. }
  1017.  
  1018. void
  1019. AppendSigned(
  1020.         StringPtr                result,
  1021.         signed long                value
  1022.     )
  1023. {
  1024.         if (value < 0) {
  1025.             AppendChar(result, '-');
  1026.             value = (-value);
  1027.         }
  1028.         AppendUnsigned(result, (unsigned long) value);
  1029. }
  1030.  
  1031. void
  1032. AppendUnsigned(
  1033.         StringPtr                result,
  1034.         unsigned long            value
  1035.     )
  1036. {
  1037.         if (value >= 10)
  1038.             AppendUnsigned(result, value / 10);
  1039.         AppendChar(result, (value % 10) + '0');
  1040. }
  1041.  
  1042. void
  1043. ClearMemory(
  1044.         register Ptr            memPtr,
  1045.         register Size            memSize
  1046.     )
  1047. {
  1048.         while (memSize > 0) {
  1049.             *memPtr++ = 0;
  1050.             --memSize;
  1051.         }
  1052. }
  1053.